import { exec, getCode, halt } from '@/utils';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';
import dayjs from 'dayjs';
import { resolve } from 'path';

@Injectable()
export class HuifuService {
  private readonly apiUrl: string;
  private readonly notifyUrl: string;
  private readonly returnUrl: string;
  private readonly merCustId: string;
  private readonly pfxFilePath: string;
  private readonly pfxPassword: string;
  private readonly cerFilePath: string;

  constructor(private readonly config: ConfigService) {
    this.apiUrl = this.config.get('huifu.apiUrl');
    this.notifyUrl = this.config.get('huifu.notifyUrl');
    this.returnUrl = this.config.get('huifu.returnUrl');
    this.merCustId = this.config.get('huifu.merCustId');
    this.pfxFilePath = this.config.get('huifu.pfxFilePath');
    this.pfxPassword = this.config.get('huifu.pfxPassword');
    this.cerFilePath = this.config.get('huifu.cerFilePath');
  }

  get NotifyUrl() {
    return this.notifyUrl;
  }

  get ReturnUrl() {
    return this.returnUrl;
  }

  async generateOrderNo() {
    return `${dayjs().format('YYYYMMDDHHmmss')}${await getCode(11)}`;
  }

  async pay033(params: any) {
    const data = {
      ...this.getParams(),
      ret_url: `${this.returnUrl}/mine`,
      bg_ret_url: `${this.notifyUrl}/api/order/callback`,
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/hfpwallet/pay033`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async pay066(params: any) {
    const data = {
      ...this.getParams(),
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/hfpay/pay006`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async qry001(params: any) {
    const data = {
      ...this.getParams(),
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/alse/qry001`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async qry008(params: any) {
    const data = {
      ...this.getParams(),
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/alse/qry008`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async qry009(params: any) {
    const data = {
      ...this.getParams(),
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/alse/qry009`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async reb001(params: any) {
    const data = {
      ...this.getParams(),
      ...params,
    };

    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/hfpay/reb001`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async reb002(params: any) {
    const data = {
      ...this.getParams(),
      ...params,
    };

    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/hfpay/reb002`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async openAccount(params: any) {
    const data = {
      ...this.getParams(),
      market_type: 2,
      acct_usage_type: 'wallet',
      ret_url: `${this.returnUrl}/mine`,
      bg_ret_url: `${this.notifyUrl}/api/huifu/wallet/callback`,
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/hfpwallet/w00003`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async accessAccount(params: any) {
    const data = {
      ...this.getParams(),
      ret_url: `${this.returnUrl}/mine`,
      ...params,
    };
    const postBody = this.getPostBody(await this.getSign(data));
    return await axios
      .post(`${this.apiUrl}/hfpwallet/w00004`, postBody, {
        headers: {
          ...this.getHeaders(),
        },
      })
      .then((res) => this.verifySign(res.data.check_value));
  }

  async getSign(value: any) {
    const res = await exec(`${resolve(__dirname, '../../huifu/main.py')}`, [
      'get_sign',
      `${resolve(__dirname, `../../huifu/${this.pfxFilePath}`)}`,
      this.pfxPassword,
      JSON.stringify(value),
    ]);
    if (!res) {
      console.error('加签失败', res);
      return halt('加签失败');
    }
    const data = JSON.parse(res);
    if (data.code !== 0) {
      console.error('加签失败', data);
    }
    return data.value;
  }

  async verifySign(value: string) {
    const res = await exec(`${resolve(__dirname, '../../huifu/main.py')}`, [
      'check_sign',
      value,
      `${resolve(__dirname, `../../huifu/${this.cerFilePath}`)}`,
    ]);
    if (!res) {
      console.error('验签失败', res);
      return halt('验签失败');
    }
    const data = JSON.parse(res);
    return JSON.parse(data.value);
  }

  public mapPayType(transType: string) {
    switch (transType) {
      case '3':
        return '12';
      case '6':
        return '15';
      case '10':
        return '22';
      case '12':
        return '27';
      default:
        return '30';
    }
  }

  private getPostBody(sign: string) {
    return `version=10&mer_cust_id=${this.merCustId}&check_value=${sign}`;
  }

  private getParams() {
    return {
      version: '10',
      mer_cust_id: this.merCustId,
    };
  }

  private getHeaders() {
    return {
      'Content-Type': 'application/x-www-form-urlencoded',
    };
  }
}
